;============================================================
; Create Time:			2020 04 26 13:01:14
; Last modify:			2020 05 08 13:07:30
; Writer:				Wenhao	1795902848@qq.com
; File Name:			main.asm
; File Type:			ASM Source File
; Tool:					DosBox -- vim7.4 & masm5.0
; Information:			
;			This is a Student info system, running
;	in dos enviroment.
;			
; Project structure:
;				 ----- main.asm
;					\_ macro.asm
;============================================================
include .\macro.asm

data segment
	students STUDENT MAX_STU_NUM dup(<>)
	score_seg db 5 dup(0)
	stu_num db 0
	buffer db 30 dup(0)
	instru_ok db 0

	;len is 53
	logo0  db "=================================================    "
	logo1  db "    ___       ___________________                    "
	logo2  db "  / ___ \     \_______   _______/                    "
	logo3  db " / /   \ \            | |                            "
	logo4  db "| |     \_\           | |                            "
	logo5  db " \ \                  | |                  .---:)    "
	logo6  db "   \ \                | |                 .          "
	logo7  db "     \ \              | |                 .          "
	logo8  db "       \ \            | |         [%]   [%]          "
	logo9  db " /\     \ |           | |         |*|   |*|          "
	logo10 db "| |     / |           | |         |*|   |*|          "
	logo11 db " \ \___/ /            | |         | \___/ |          "
	logo12 db "  \ ___ /             \_/          \_____/           "
	logo13 db "=================================================    "

	wenhao0 db "Welcome to Wenhao's student info system!"
	wenhao1 db "New to this system? Type"
	helpword db "help"
	wenhao2 db "to get started."

	;len 59
	man0 db " exit                   Exit this program                  "
	man1 db " input                  Input a student's info             "
	man2 db " sort by id             Sort students's info by id         "
	man3 db " sort by age            Sort students's info by age        "
	man4 db " sort by score          Sort students's info by score      "
	man5 db " show all               Output all students' info on screen"
	man6 db " show avg               Output average score               "
	man7 db " show seg               Output student num in score segs   "
	man8 db " cls                    Clear the screen                   "

	;32
	data_overflow db "Data base overflow! Input denyed"
	;17
	promt_input_name db "Input stu's name:"
	;65
	error_input_name db "Error: name is too long or too short. Correct length is in [1, 9]"
	;16
	promt_input_age db "Input stu's age:"
	;68
	error_input_age db "Error: age is too big or too small. Correct age locates in [10, 100]"
	;15
	promt_input_id db "Input stu's id:"
	;46
	error_input_id db "Error: illegal id length. Correct length is 10"
	;19
	promt_input_score db "Input stud's score:"
	;61
	error_input_score db "Error: score illegal. Correct score is an integer in [0, 100]"
	;48
	error_str_has_non_digtal db "Error: non-digtal involved in your inputed words"
	;19
	sort_finished db "Info: sort finished"
	;25
	total_stu_num db "Total students number is:"
	;17
	average_score db "Average score is:"
	;27
	empty_data db "Error: There is no data yet"
data ends

stack segment stack
	db STACK_DEPTH dup(0)
stack ends

code segment
	assume cs:code, ds:data, ss:stack
start:
	mov ax, data
	mov ds, ax
	mov es, ax
	call Clr_screen
	call Init
	call RewriteInt8
s:
	call Input_instruction
	call Execute_instruction
	call Up_shift_screen
	jmp s					;Main loop. All services are in this loop.

;---------------------------------------------------;
;		The service functions are defined below		;
;---------------------------------------------------;


;========================================
;		Init. Show some cool messages on
;	screen
;========================================
Init:
	outputstr logo0,  53, 1,  13, 111b
	outputstr logo1,  53, 2,  13, 111b
	outputstr logo2,  53, 3,  13, 111b
	outputstr logo3,  53, 4,  13, 111b
	outputstr logo4,  53, 5,  13, 111b
	outputstr logo5,  53, 6,  13, 111b
	outputstr logo6,  53, 7,  13, 111b
	outputstr logo7,  53, 8,  13, 111b
	outputstr logo8,  53, 9,  13, 111b
	outputstr logo9,  53, 10, 13, 111b
	outputstr logo10, 53, 11, 13, 111b
	outputstr logo11, 53, 12, 13, 111b
	outputstr logo12, 53, 13, 13, 111b
	outputstr logo13, 53, 14, 13, 111b

	outputstr wenhao0, 40, 15, 2, 111b
	outputstr wenhao1, 24, 16, 2, 111b
	outputstr helpword, 4, 16, 27, 010b
	outputstr wenhao2, 15, 16, 32, 111b
ret


;========================================
;		fill all screen with space
;========================================
Clr_screen:
	push ax
	push es
	push di
	push cx

	mov ax, 0b800h
	mov es, ax
	mov di, 0
	mov cx, 2000
cls_s:
	mov byte ptr es:[di], ' '
	inc di
	mov byte ptr es:[di], 0
	inc di
	loop cls_s

	pop cx
	pop di
	pop es
	pop ax
ret

;========================================
;		input a char
;	ah holds the scan code
;	al holds the ASCII code
;========================================
Input_char:
	mov ah, 0
	int 16h
ret

;========================================
;		Input instruction and show
;========================================
Input_instruction:
	push ax
	push es
	push di
	push si

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*24]
	call Show_promt_char
	call Input_to_buff

	call Strip_buff
	call Up_shift_screen

	pop si
	pop di
	pop es
	pop ax
ret

;========================================
;		Input string to buffer
;========================================
Input_to_buff:
	mov si, 0
input_instru_loop:
	mov byte ptr es:[di], ' '
	mov byte ptr es:[di+1], 01110000b

	call Input_char
	cmp ah, 1ch				;cmp if it is <enter> or not
	je input_instru_end

	cmp ah, 0eh				;cmp if it is <delete> or not
	je delete_char

	mov es:[di], al
	inc di
	mov byte ptr es:[di], 111b
	inc di

	mov buffer[si], al
	inc si

	jmp input_instru_loop

delete_char:
	cmp si, 0
	je input_instru_loop

	mov word ptr es:[di], 0

	dec si
	dec di
	dec di

	mov word ptr es:[di], 0

	jmp input_instru_loop

input_instru_end:
	mov word ptr es:[di], 0
	mov buffer[si], 0
ret

;========================================
;		Strip space around buff.
;========================================
Strip_buff:
	push bx
	push si
	push ax

	mov bx, 0
	mov si, 0

	;scan from left to right
	;find non-space pos
strip_left:
	cmp buffer[si], ' '
	jne copy
	inc si
	jmp strip_left

	;copy from the first non-space char
copy:
	cmp buffer[si], 0
	je strip_right

	mov al, buffer[si]
	mov buffer[bx], al

	inc si
	inc bx

	jmp copy

	;find the last non-space pos
strip_right:
	dec bx
	cmp buffer[bx], ' '
	jne strip_end
	jmp strip_right

	;write 0 to buffer's end
strip_end:

	mov buffer[bx][1], 0

	pop ax
	pop si
	pop bx
ret

;========================================
;		Show promting character
;========================================
Show_promt_char:
	output_char '[', 1100b
	output_char 's', 011b
	output_char 't', 011b
	output_char 'u', 011b
	output_char 'd', 011b
	output_char 'e', 011b
	output_char 'n', 011b
	output_char 't', 011b
	output_char ']', 1100b
	output_char ' ', 0
ret

;========================================
;		Up shift screen
;========================================
Up_shift_screen:
	push es
	push cx
	push di
	push ax

	mov ax, 0b800h
	mov es, ax

	mov cx, 3840		;24*160
	mov di, 0

up_shift_loop:
	mov al, es:[di][160]
	mov es:[di], al
	inc di
	loop up_shift_loop

	mov cx, 160
clear_last_line:
	mov byte ptr es:[di], 0
	inc di
	loop clear_last_line

	pop ax
	pop di
	pop cx
	pop es
ret

;========================================
;		Check the instruction in buffer,
;	and execute accordingly.
;========================================
Execute_instruction:
	mov instru_ok, 0

	cmp buffer[0], 0			;if empty instruction, return.
	jne chk_exit				;else, find out what to execute.

	pop ax						;The func is too long to jump
	jmp ax						;to its end. Here uses jmp to
								;return from this func.
chk_exit:
	call Chk_do_exit
	cmp instru_ok, 1
	jne chk_sort_by_score
	call Exit_program
	jmp end_exe

chk_sort_by_score:
	call Chk_do_sort_by_score
	cmp instru_ok, 1
	jne chk_sort_by_id
	call Sort_by_score
	jmp end_exe

chk_sort_by_id:
	call Chk_do_sort_by_id
	cmp instru_ok, 1
	jne chk_sort_by_age
	call Sort_by_id
	jmp end_exe

chk_sort_by_age:
	call Chk_do_sort_by_age
	cmp instru_ok, 1
	jne chk_show_all
	call Sort_by_age
	jmp end_exe

chk_show_all:
	call Chk_do_show_all
	cmp instru_ok, 1
	jne chk_input_info
	call Show_all
	jmp end_exe

chk_input_info:
	call Chk_do_input_info
	cmp instru_ok, 1
	jne chk_show_avg_score
	cmp stu_num, MAX_STU_NUM
	jb free_to_input_info

	;too much data!
	outputstr data_overflow, 32, 24, 1, 100b
	jmp end_exe

free_to_input_info:
	call Input_info
	mov al, stu_num
	inc al
	mov stu_num, al

	jmp end_exe

chk_show_avg_score:
	call Chk_do_show_avg_score
	cmp instru_ok, 1
	jne chk_show_score_seg
	call Show_avg
	jmp end_exe

chk_show_score_seg:
	call Chk_do_show_score_seg
	cmp instru_ok, 1
	jne chk_cls
	call Show_seg
	jmp end_exe

chk_cls:
	call Chk_do_clear_screen
	cmp instru_ok, 1
	jne chk_help
	call Clr_screen
	jmp end_exe

chk_help:
	call Chk_do_help
	cmp instru_ok, 1
	jne default_func
	call Help
	jmp end_exe

default_func:
	call Inst_Error_Cmd			;Default, error instruction.
end_exe:
ret


;========================================
;		Instruction: Error Instruction
;	Inst means : instruction
;========================================
Inst_Error_Cmd:
	push ax
	push es
	push si
	push di
	
	mov ax, 0b800h
	mov es, ax
	mov di, 3840		;160 * 24
	mov si, 0

	output_char 'E', 100b
	output_char 'R', 100b
	output_char 'R', 100b
	output_char 'O', 100b
	output_char 'R', 100b
	output_char ':', 100b
	output_char ' ', 100b

echo_inst:
	cmp buffer[si], 0
	je echo_inst_end
	mov al, buffer[si]
	inc si
	and al, 11011111b
	output_char al, 110b
	jmp echo_inst

echo_inst_end:
	output_char '-', 100b
	output_char '-', 100b
	output_char 'C', 100b
	output_char 'O', 100b
	output_char 'M', 100b
	output_char 'M', 100b
	output_char 'A', 100b
	output_char 'N', 100b
	output_char 'D', 100b
	output_char ' ', 100b
	output_char 'N', 100b
	output_char 'O', 100b
	output_char 'T', 100b
	output_char ' ', 100b
	output_char 'F', 100b
	output_char 'O', 100b
	output_char 'U', 100b
	output_char 'N', 100b
	output_char 'D', 100b

	pop di
	pop si
	pop es
	pop ax

ret

;========================================
;		Instruction: Exit the program
;========================================
Exit_program:
	call RestoreInt8
	mov ax, 4c00h
	int 21h
ret

;========================================
;		Check whether the instruction in
;	buffer is legal to call func exit.
;========================================
Chk_do_exit:
	cmp buffer[0], 'e'
	jne chk_do_exit_end
	cmp buffer[1], 'x'
	jne chk_do_exit_end
	cmp buffer[2], 'i'
	jne chk_do_exit_end
	cmp buffer[3], 't'
	jne chk_do_exit_end
	cmp buffer[4], 0
	jne chk_do_exit_end

	mov byte ptr instru_ok, 1
	ret

chk_do_exit_end:
ret

;========================================
;		Check whether to sort student info.
;	sort by score.
;========================================
Chk_do_sort_by_score:
	cmp buffer[0], 's'
	jne chk_do_sort_by_score_end
	cmp buffer[1], 'o'
	jne chk_do_sort_by_score_end
	cmp buffer[2], 'r'
	jne chk_do_sort_by_score_end
	cmp buffer[3], 't'
	jne chk_do_sort_by_score_end
	cmp buffer[4], ' '
	jne chk_do_sort_by_score_end
	cmp buffer[5], 'b'
	jne chk_do_sort_by_score_end
	cmp buffer[6], 'y'
	jne chk_do_sort_by_score_end
	cmp buffer[7], ' '
	jne chk_do_sort_by_score_end
	cmp buffer[8], 's'
	jne chk_do_sort_by_score_end
	cmp buffer[9], 'c'
	jne chk_do_sort_by_score_end
	cmp buffer[10], 'o'
	jne chk_do_sort_by_score_end
	cmp buffer[11], 'r'
	jne chk_do_sort_by_score_end
	cmp buffer[12], 'e'
	jne chk_do_sort_by_score_end
	cmp buffer[13], 0
	jne chk_do_sort_by_score_end

	mov byte ptr instru_ok, 1
	ret

chk_do_sort_by_score_end:
ret

;========================================
;		Cmp func. cmp by score
;	To be cmped students' bias in mem are:
;	<bx>, <si>
;========================================
Cmp_by_score:
	mov al, ds:[bx][SCORE_BIAS]
	cmp al, ds:[si][SCORE_BIAS]
	ja score_bigger
	mov al, 0
	ret

score_bigger:
	mov al, 1
ret

;========================================
;		Cmp func. cmp by id
;========================================
Cmp_by_id:
	push bx
	push si
	push cx

	mov cx, 10
cmp_by_id_loop:
	mov al, ds:[bx][ID_BIAS]
	cmp al, ds:[si][ID_BIAS]
	ja id_bigger
	jb id_smaller

	inc bx
	inc si
	loop cmp_by_id_loop

id_smaller:
	pop cx
	pop si
	pop bx
	mov al, 0
	ret

id_bigger:
	pop cx
	pop si
	pop bx
	mov al, 1
ret

;========================================
;		Cmp func. cmp by age
;========================================
Cmp_by_age:
	mov al, ds:[bx][AGE_BIAS]
	cmp al, ds:[si][AGE_BIAS]
	ja age_bigger
	mov al, 0
	ret
age_bigger:
	mov al, 1
ret

;========================================
;		Swap two student's info
;	Two student's bias are: <bx>, <si>
;	Alias students are : A, B
;========================================
Swap:
	push di
	push es
	push si
	push cx

	mov di, ds				;preparation before copying
	mov es, di
	mov cx, STU_SIZE

	lea di, buffer[2]
	push cx					;save regs to stack
	push si
	push di
	cld
	rep movsb				;copy B to buffer
	pop di					;restore regs
	pop si
	pop cx

	push si
	mov si, bx
	pop di
	
	push cx					;save regs to stack
	push si
	push di
	rep movsb				;copy A to B
	pop di
	pop si
	pop cx

	mov di, si
	lea si, buffer[2]
	rep movsb				;copy buffer to A

	pop cx
	pop si
	pop es
	pop di
ret

;========================================
;		Sort students' info.
;	The cmp func is in buffer.
;========================================
Bubble_sort:
	push ax
	push si
	push cx
	push dx

	mov cl, stu_num
	mov ch, 0
	dec cx
	cmp cx, 0
	je outer_loop_end
	mov dx, 0

outer_loop:
	push cx

	mov cl, stu_num
	mov ch, 0
	dec cx
	sub cx, dx
	cmp cx, 0
	je inner_loop_end
	mov bx, 0
	mov si, STU_SIZE
inner_loop:
	call word ptr buffer
	cmp al, 1
	jne cmp_flag
	call Swap
cmp_flag:
	add bx, STU_SIZE
	add si, STU_SIZE
	loop inner_loop

inner_loop_end:
	pop cx
	inc dx
	loop outer_loop
outer_loop_end:
	pop dx
	pop cx
	pop si
	pop ax
ret


;========================================
;		Sort students' info by score
;========================================
Sort_by_score:
	cmp stu_num, 0
	je sort_by_score_empty_data
	push ax
	push bx

	lea ax, Cmp_by_score
	lea bx, buffer
	mov ds:[bx], ax

	call Bubble_sort
	outputstr sort_finished, 19, 24, 0, 101b

	pop bx
	pop ax
	ret

sort_by_score_empty_data:
	outputstr empty_data, 27, 24, 1, 100b
ret

;========================================
;		Sort students' info by id
;========================================
Sort_by_id:
	cmp stu_num, 0
	je sort_by_id_empty_data
	push ax
	push bx

	lea ax, Cmp_by_id
	lea bx, buffer
	mov ds:[bx], ax

	call Bubble_sort
	outputstr sort_finished, 19, 24, 0, 101b

	pop bx
	pop ax
	ret

sort_by_id_empty_data:
	outputstr empty_data, 27, 24, 1, 100b
ret


;========================================
;		Sort students' info by age
;========================================
Sort_by_age:
	cmp stu_num, 0
	je sort_by_age_empty_data
	push ax
	push bx

	lea ax, Cmp_by_age
	lea bx, buffer
	mov ds:[bx], ax

	call Bubble_sort
	outputstr sort_finished, 19, 24, 0, 101b

	pop bx
	pop ax
	ret

sort_by_age_empty_data:
	outputstr empty_data, 27, 24, 1, 100b
ret

;========================================
;		Check whether to sort student info.
;	sort by id.
;========================================
Chk_do_sort_by_id:
	cmp buffer[0], 's'
	jne chk_do_sort_by_id_end
	cmp buffer[1], 'o'
	jne chk_do_sort_by_id_end
	cmp buffer[2], 'r'
	jne chk_do_sort_by_id_end
	cmp buffer[3], 't'
	jne chk_do_sort_by_id_end
	cmp buffer[4], ' '
	jne chk_do_sort_by_id_end
	cmp buffer[5], 'b'
	jne chk_do_sort_by_id_end
	cmp buffer[6], 'y'
	jne chk_do_sort_by_id_end
	cmp buffer[7], ' '
	jne chk_do_sort_by_id_end
	cmp buffer[8], 'i'
	jne chk_do_sort_by_id_end
	cmp buffer[9], 'd'
	jne chk_do_sort_by_id_end
	cmp buffer[10], 0
	jne chk_do_sort_by_id_end

	mov byte ptr instru_ok, 1
	ret

chk_do_sort_by_id_end:
ret

;========================================
;		Check whether to sort student info.
;	sort by age.
;========================================
Chk_do_sort_by_age:
	cmp buffer[0], 's'
	jne chk_do_sort_by_age_end
	cmp buffer[1], 'o'
	jne chk_do_sort_by_age_end
	cmp buffer[2], 'r'
	jne chk_do_sort_by_age_end
	cmp buffer[3], 't'
	jne chk_do_sort_by_age_end
	cmp buffer[4], ' '
	jne chk_do_sort_by_age_end
	cmp buffer[5], 'b'
	jne chk_do_sort_by_age_end
	cmp buffer[6], 'y'
	jne chk_do_sort_by_age_end
	cmp buffer[7], ' '
	jne chk_do_sort_by_age_end
	cmp buffer[8], 'a'
	jne chk_do_sort_by_age_end
	cmp buffer[9], 'g'
	jne chk_do_sort_by_age_end
	cmp buffer[10], 'e'
	jne chk_do_sort_by_age_end
	cmp buffer[11], 0
	jne chk_do_sort_by_age_end

	mov byte ptr instru_ok, 1
	ret

chk_do_sort_by_age_end:
ret

;========================================
;		Check whether to show all students's
;	info. The info is ether sorted or
;	in input order.
;========================================
Chk_do_show_all:
	cmp buffer[0], 's'
	jne chk_do_show_all_end
	cmp buffer[1], 'h'
	jne chk_do_show_all_end
	cmp buffer[2], 'o'
	jne chk_do_show_all_end
	cmp buffer[3], 'w'
	jne chk_do_show_all_end
	cmp buffer[4], ' '
	jne chk_do_show_all_end
	cmp buffer[5], 'a'
	jne chk_do_show_all_end
	cmp buffer[6], 'l'
	jne chk_do_show_all_end
	cmp buffer[7], 'l'
	jne chk_do_show_all_end
	cmp buffer[8], 0
	jne chk_do_show_all_end

	mov byte ptr instru_ok, 1
	ret

chk_do_show_all_end:
ret

;========================================
;		Display all students' info on
;	screen.
;========================================
Show_all:
	push cx
	push bx
	push di
	push es

	lea di, ds:[160*24]
	mov cx, 0b800h
	mov es, cx

	mov cx, 0
	mov cl, stu_num

	cmp cx, 0
	je empty_data_to_show

	mov bx, 0

	call Display_header
	call Up_shift_screen

show_all_loop:
	call Output_name
	call Output_age
	call Output_id
	call Output_score
	cmp cx, 1
	je last_line_dont_up_shift
	call Up_shift_screen
last_line_dont_up_shift:
	add bx, STU_SIZE
	loop show_all_loop
	jmp end_show

empty_data_to_show:
	mov cx, ds
	mov es, cx
	outputstr empty_data, 27, 24, 1, 100b
end_show:

	pop es
	pop di
	pop bx
	pop cx
ret

;========================================
;	Display header for info.
;========================================
Display_header:
	push ax
	push es
	push di

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*24 + 2*2]
	output_char 'n', 101b
	output_char 'a', 101b
	output_char 'm', 101b
	output_char 'e', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b

	output_char 'a', 101b
	output_char 'g', 101b
	output_char 'e', 101b
	output_char ' ', 101b

	output_char 'i', 101b
	output_char 'd', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b

	output_char 's', 101b
	output_char 'c', 101b
	output_char 'o', 101b
	output_char 'r', 101b
	output_char 'e', 101b

	pop di
	pop es
	pop ax
ret

;========================================
;		Output name to last line
;	<bx> holds bias of current student's
;	table
;	<di> has already be given the last 
;	line's bias
;	<es> = 0b800h
;========================================
Output_name:
	push di
	push ax
	mov si, 0
output_name_loop:
	cmp byte ptr ds:[bx][si], 0
	je output_name_loop_end
	mov al, ds:[bx][si]
	inc si
	mov es:[di][2*2], al
	inc di
	mov byte ptr es:[di][2*2], 111b
	inc di
	jmp output_name_loop

output_name_loop_end:
	pop ax
	pop di
ret

;========================================
;		Output age to last line.
;========================================
Output_age:
	push ax
	push bx
	push di

	mov ax, 0
	mov al, ds:[bx][10]

	mov bx, 10
	div bl
	add al, '0'
	add ah, '0'

	mov es:[di][2*11], al
	inc di
	mov byte ptr es:[di][2*11], 111b
	inc di

	mov es:[di][2*11], ah
	inc di
	mov byte ptr es:[di][2*11], 111b
	inc di

	pop di
	pop bx
	pop ax
ret

;========================================
;		Output student's id to screen
;========================================
Output_id:
	push di
	push si
	push cx

	mov si, 0
	mov cx, 10
output_id_loop:
	mov al, ds:[bx][si][11]
	inc si
	mov es:[di][2*15], al
	inc di
	mov byte ptr es:[di][2*15], 111b
	inc di
	loop output_id_loop

	pop cx
	pop si
	pop di
ret

;========================================
;		Output student's score to screen
;========================================
Output_score:
	push ax
	push bx
	push di

	mov ax, 0
	mov al, ds:[bx][21]
	cmp al, 100
	jne not_100
	mov byte ptr es:[di][2*26], '1'
	inc di
	mov byte ptr es:[di][2*26], 111b
	inc di
	mov byte ptr es:[di][2*26], '0'
	inc di
	mov byte ptr es:[di][2*26], 111b
	inc di
	mov byte ptr es:[di][2*26], '0'
	inc di
	mov byte ptr es:[di][2*26], 111b
	inc di
	jmp show_score_end

not_100:
	mov bx, 10
	div bl
	cmp al, 0
	je skip_zero

	add al, '0'
	mov es:[di][2*26], al
	inc di
	mov byte ptr es:[di][2*26], 111b
	inc di

skip_zero:
	add ah, '0'
	mov es:[di][2*26], ah
	inc di
	mov byte ptr es:[di][2*26], 111b
	inc di
show_score_end:
	pop di
	pop bx
	pop ax
ret

;========================================
;		Display <ax> in decades to screen
;	Bias is already be given in (es:di)
;	Assuming <ax> < 100
;========================================
Display_num_in_decades:
	push bx
	push ax

	mov bx, 10
	div bl
	cmp al, 0
	je is_zero					;when al <= 9
	cmp al, 10
	je is_ten
	add al, '0'
is_zero:
	mov byte ptr es:[di], al
	inc di
	mov byte ptr es:[di], 111b
	inc di
	jmp is_ten_end

is_ten:
	mov byte ptr es:[di], '1'
	inc di
	mov byte ptr es:[di], 111b
	inc di
	mov byte ptr es:[di], '0'
	inc di
	mov byte ptr es:[di], 111b
	inc di

is_ten_end:

	add ah, '0'
	mov byte ptr es:[di], ah
	inc di
	mov byte ptr es:[di], 111b
	inc di

	pop ax
	pop bx

ret

;========================================
;		Display average score of all
;	students.
;========================================
Show_avg:
	cmp stu_num, 0
	jne show_avg_start
	outputstr empty_data, 27, 24, 1, 100b
	jmp show_avg_end

show_avg_start:
	push es
	push ds
	push ax
	push bx
	push cx
	push dx
	push di

	outputstr total_stu_num, 25, 24, 2, 111b
	push es						;save es to stack, es = ds now

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*24 + 2* 27]

	mov al, stu_num
	mov ah, 0
	call Display_num_in_decades;display stu num
	call Up_shift_screen

	pop es
	outputstr average_score, 17, 24, 2, 111b

	mov ax, 0					;ax saves sum of total score
	mov bx, 0					;bx is student info bias
	mov dx, 0
	mov cl, stu_num
	mov ch, 0
	cmp cx, 0
	je get_total_score_end
get_total_score:
	mov dl, ds:[bx][SCORE_BIAS]
	add ax, dx
	add bx, STU_SIZE
	loop get_total_score
get_total_score_end:

	mov bx, 10

	div byte ptr stu_num
	push ax
	mov ah, 0					;display al in decades

	mov cx, 0b800h
	mov es, cx
	lea di, ds:[160*24 + 2* 20]
	call Display_num_in_decades
	output_char '.', 111b

	pop ax
	mov cx, 8
	shr ax, cl					;display ah/stu_num in decades
	mov ch, 10
	mul ch
	div byte ptr stu_num
	mov ah, 0
	add al, '0'

	mov es:[di], al
	mov byte ptr es:[di+1], 111b

	pop di
	pop dx
	pop cx
	pop bx
	pop ax
	pop ds
	pop es
show_avg_end:
ret

;========================================
;		Display students' num in score
;	segs:
;		[0, 60)
;		[60, 70)
;		[70, 80)
;		[80, 90)
;		[90, 100]
;========================================
Show_seg:
	cmp stu_num, 0
	jne show_seg_start
	outputstr empty_data, 27, 24, 1, 100b
	jmp show_seg_end

show_seg_start:
	mov word ptr score_seg[0], 0
	mov word ptr score_seg[2], 0
	mov byte ptr score_seg[4], 0

	push cx
	push bx
	push ax
	push es
	push di

	mov cx, 0
	mov cl, stu_num

	mov bx, 0
count_seg_loog:
	mov al, ds:[bx][SCORE_BIAS]
	add bx, STU_SIZE
	cmp al, 60
	jae score_60_to_70
	increase score_seg[0]
	jmp score_continue_loop
score_60_to_70:
	cmp al, 70
	jae score_70_to_80
	increase score_seg[1]
	jmp score_continue_loop
score_70_to_80:
	cmp al, 80
	jae score_80_to_90
	increase score_seg[2]
	jmp score_continue_loop
score_80_to_90:
	cmp al, 90
	jae score_90_to_100
	increase score_seg[3]
	jmp score_continue_loop
score_90_to_100:
	increase score_seg[4]
score_continue_loop:
	loop count_seg_loog

	mov ax, 0b800h					;output score seg infomation
	mov es, ax
	mov ax, 0
	lea di, ds:[160*24 + 2*2]

	output_char 's', 101b
	output_char 'c', 101b
	output_char 'o', 101b
	output_char 'r', 101b
	output_char 'e', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char ' ', 101b
	output_char 'n', 101b
	output_char 'u', 101b
	output_char 'm', 101b

	call Up_shift_screen
	lea di, ds:[160*24 + 2*2]
	output_char '[', 111b
	output_char '0', 111b
	output_char ',', 111b
	output_char ' ', 111b
	output_char '6', 111b
	output_char '0', 111b
	output_char ')', 111b
	output_char ' ', 111b
	output_char ' ', 111b
	output_char ' ', 111b
	mov al, score_seg[0]
	call Display_num_in_decades

	call Up_shift_screen
	lea di, ds:[160*24 + 2*2]
	output_char '[', 111b
	output_char '6', 111b
	output_char '0', 111b
	output_char ',', 111b
	output_char ' ', 111b
	output_char '7', 111b
	output_char '0', 111b
	output_char ')', 111b
	output_char ' ', 111b
	output_char ' ', 111b
	mov al, score_seg[1]
	call Display_num_in_decades

	call Up_shift_screen
	lea di, ds:[160*24 + 2*2]
	output_char '[', 111b
	output_char '7', 111b
	output_char '0', 111b
	output_char ',', 111b
	output_char ' ', 111b
	output_char '8', 111b
	output_char '0', 111b
	output_char ')', 111b
	output_char ' ', 111b
	output_char ' ', 111b
	mov al, score_seg[2]
	call Display_num_in_decades

	call Up_shift_screen
	lea di, ds:[160*24 + 2*2]
	output_char '[', 111b
	output_char '8', 111b
	output_char '0', 111b
	output_char ',', 111b
	output_char ' ', 111b
	output_char '9', 111b
	output_char '0', 111b
	output_char ')', 111b
	output_char ' ', 111b
	output_char ' ', 111b
	mov al, score_seg[3]
	call Display_num_in_decades

	call Up_shift_screen
	lea di, ds:[160*24 + 2*2]
	output_char '[', 111b
	output_char '9', 111b
	output_char '0', 111b
	output_char ',', 111b
	output_char ' ', 111b
	output_char '1', 111b
	output_char '0', 111b
	output_char '0', 111b
	output_char ']', 111b
	output_char ' ', 111b
	mov al, score_seg[4]
	call Display_num_in_decades

	pop di
	pop es
	pop ax
	pop bx
	pop cx
show_seg_end:
ret

;========================================
;		Check whether the instruction is
;	legal to input a student's info.
;========================================
Chk_do_input_info:
	cmp buffer[0], 'i'
	jne chk_do_input_end
	cmp buffer[1], 'n'
	jne chk_do_input_end
	cmp buffer[2], 'p'
	jne chk_do_input_end
	cmp buffer[3], 'u'
	jne chk_do_input_end
	cmp buffer[4], 't'
	jne chk_do_input_end
	cmp buffer[5], 0
	jne chk_do_input_end

	mov byte ptr instru_ok, 1
	ret

chk_do_input_end:
ret

;========================================
;		Input a student's info
;========================================
Input_info:
	push ax
	push bx
	push es
	push di

	mov ax, STU_SIZE
	mul stu_num
	mov bx, ax

input_name_loop:
	outputstr promt_input_name, 17, 24, 1, 111b
	push es						;es equals ds

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*24 + 2*22]
	call Input_to_buff
	call Strip_buff
	call Write_name_to_table
	cmp al, 1
	je input_age_loop_init		;go to input age if name is legal

	pop es
	call Up_shift_screen
	outputstr error_input_name, 65, 24, 1, 100b
	call Up_shift_screen
	jmp input_name_loop

input_age_loop_init:
	pop es
	call Up_shift_screen
input_age_loop:
	outputstr promt_input_age, 16, 24, 1, 111b
	push es

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*24 + 2*22]
	call Input_to_buff
	call Strip_buff
	call Write_age_to_table
	cmp al, 1
	je input_id_loop_init

	pop es
	call Up_shift_screen
	cmp al, 0
	je input_age_show_error

	outputstr error_str_has_non_digtal, 48, 24, 1, 100b
	call Up_shift_screen
	jmp input_age_loop

input_age_show_error:
	outputstr error_input_age, 68, 24, 1, 100b
	call Up_shift_screen
	jmp input_age_loop

input_id_loop_init:
	pop es
	call Up_shift_screen
input_id_loop:
	outputstr promt_input_id, 15, 24, 1, 111b
	push es

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*24 + 2*22]
	call Input_to_buff
	call Strip_buff
	call Write_id_to_table
	cmp al, 1
	je input_score_loop_init

	pop es
	call Up_shift_screen
	cmp al, 0
	je input_id_show_error

	outputstr error_str_has_non_digtal, 48, 24, 1, 100b
	call Up_shift_screen
	jmp input_id_loop

input_id_show_error:
	outputstr error_input_id, 46, 24, 1, 100b
	call Up_shift_screen
	jmp input_id_loop

input_score_loop_init:
	pop es
	call Up_shift_screen
input_score_loop:
	outputstr promt_input_score, 19, 24, 1, 111b
	push es

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*24 + 2*22]
	call Input_to_buff
	call Strip_buff
	call Write_score_to_table
	cmp al, 1
	je end_input

	pop es
	call Up_shift_screen
	outputstr error_input_score, 61, 24, 1, 100b
	call Up_shift_screen
	jmp input_score_loop

end_input:
	pop es

	pop di
	pop es
	pop bx
	pop ax
ret

;========================================
;		Write name from buffer to stu info
;	tables.
;		If name is too long(> 9 chars) or
;	empty, let al = 0 as return value.
;		Else, return al = 1.
;	<bx> saves the bias of student's info
;========================================
Write_name_to_table:
	mov si, 0
	cmp buffer, 0
	je write_name_error		;error when empty name
write_name_loop:
	cmp buffer[si], 0
	je write_name_ok

	cmp si, 9
	je write_name_error

	mov al, buffer[si]
	mov ds:[bx][si], al
	inc si
	jmp write_name_loop

write_name_ok:
	mov byte ptr ds:[bx][si], 0
	mov al, 1
	ret

write_name_error:
	mov al, 0
ret

;========================================
;		Age str saved in buffer in decades. 
;		Use this func to move int(age) to 
;	student info table.
;		If done successfuly, let al = 1
;		Else let al = 0
;	<bx> saves the bias of student's info
;========================================
Write_age_to_table:
	mov ax, 0
	mov si, 0
	mov cx, 10
	cmp buffer, 0
	je write_age_non_digtal			;empty age error

write_age_loop:
	cmp buffer[si], 0
	je write_age_ok
	cmp buffer[si], '0'
	jb write_age_non_digtal
	cmp buffer[si], '9'
	ja write_age_non_digtal

	mul cl
	sub buffer[si], '0'
	add al, buffer[si]
	inc si

	cmp ax, 100				;This student is too old!
	ja write_age_error

	jmp write_age_loop

write_age_ok:
	cmp ax, 10
	jb write_age_error		;This student is too young!
	mov ds:[bx][AGE_BIAS], al
	mov al, 1
	ret
write_age_non_digtal:
	mov al, 2
	ret
write_age_error:
	mov al, 0
ret

;========================================
;		Student id is saved in buffer.
;		Use this func to copy stu id to
;	student info table.
;		If done successfuly, let al = 1
;		Else
;			if len not == 10, let al = 0
;			else if has non-digtal
;				let al = 2
;========================================
Write_id_to_table:
	mov si, 0
write_id_loop:
	cmp buffer[si], 0
	je write_id_ok
	cmp buffer[si], '0'
	jb write_id_non_digtal
	cmp buffer[si], '9'
	ja write_id_non_digtal
	cmp si, 10
	je write_id_error

	mov al, buffer[si]
	mov ds:[bx][ID_BIAS][si], al
	inc si
	jmp write_id_loop

write_id_ok:
	cmp si, 10
	jne write_id_error
	mov al, 1
	ret
write_id_non_digtal:
	mov al, 2
	ret
write_id_error:
	mov al, 0
ret

;========================================
;		Check whether the instruction is
;========================================
Write_score_to_table:
	mov ax, 0
	mov si, 0
	mov cx, 10
	cmp buffer, 0
	je write_score_non_digtal

write_score_loop:
	cmp buffer[si], 0
	je write_score_ok
	cmp buffer[si], '0'
	jb write_score_non_digtal
	cmp buffer[si], '9'
	ja write_score_non_digtal

	mul cl
	sub buffer[si], '0'
	add al, buffer[si]
	inc si

	cmp ax, 100
	ja write_score_error

	jmp write_score_loop

write_score_ok:
	mov ds:[bx][SCORE_BIAS], al
	mov al, 1
	ret
write_score_non_digtal:
	mov al, 2
	ret
write_score_error:
	mov al, 0
ret

;========================================
;		Check whether the instruction is
;	legal to show students's num in the
;	following score segs:
;		[0, 60)
;		[60, 70)
;		[70, 80)
;		[80, 90)
;		[90, 100]
;========================================
Chk_do_show_score_seg:
	cmp buffer[0], 's'
	jne chk_do_show_score_seg_end
	cmp buffer[1], 'h'
	jne chk_do_show_score_seg_end
	cmp buffer[2], 'o'
	jne chk_do_show_score_seg_end
	cmp buffer[3], 'w'
	jne chk_do_show_score_seg_end
	cmp buffer[4], ' '
	jne chk_do_show_score_seg_end
	cmp buffer[5], 's'
	jne chk_do_show_score_seg_end
	cmp buffer[6], 'e'
	jne chk_do_show_score_seg_end
	cmp buffer[7], 'g'
	jne chk_do_show_score_seg_end
	cmp buffer[8], 0
	jne chk_do_show_score_seg_end

	mov byte ptr instru_ok, 1
	ret

chk_do_show_score_seg_end:
ret

;========================================
;		Check whether the instruction is
;	legal to call a func to clear screen
;========================================
Chk_do_clear_screen:
	cmp buffer[0], 'c'
	jne chk_do_cls_end
	cmp buffer[1], 'l'
	jne chk_do_cls_end
	cmp buffer[2], 's'
	jne chk_do_cls_end
	cmp buffer[3], 0
	jne chk_do_cls_end

	mov byte ptr instru_ok, 1
	ret

chk_do_cls_end:	
ret

;========================================
;		Check whether the instruction is
;	legal to call a func to show help
;	messages.
;========================================
Chk_do_help:
	cmp buffer[0], 'h'
	jne chk_do_help_end
	cmp buffer[1], 'e'
	jne chk_do_help_end
	cmp buffer[2], 'l'
	jne chk_do_help_end
	cmp buffer[3], 'p'
	jne chk_do_help_end
	cmp buffer[4], 0
	jne chk_do_help_end

	mov byte ptr instru_ok, 1
	ret
chk_do_help_end:
ret

;========================================
;		Show help messages on screen
;========================================
Help:
	push ax
	push es
	push di

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*24+2*4]
	output_char 'c', 101b
	output_char 'm', 101b
	output_char 'd', 101b

	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b
	output_char '-', 111b

	output_char 'i', 101b
	output_char 'n', 101b
	output_char 'f', 101b
	output_char 'o', 101b
	output_char 'r', 101b
	output_char 'm', 101b
	output_char 'a', 101b
	output_char 't', 101b
	output_char 'i', 101b
	output_char 'o', 101b
	output_char 'n', 101b

	pop di
	pop es
	pop ax


	outputstr man0, 59, 25, 3, 111b
	outputstr man1, 59, 25, 3, 111b
	outputstr man2, 59, 25, 3, 111b
	outputstr man3, 59, 25, 3, 111b
	outputstr man4, 59, 25, 3, 111b
	outputstr man5, 59, 25, 3, 111b
	outputstr man6, 59, 25, 3, 111b
	outputstr man7, 59, 25, 3, 111b
	outputstr man8, 59, 25, 3, 111b
ret

;========================================
;		Check whether the instruction is
;	legal to call a func to get average
;	score and output it to screen.
;========================================
Chk_do_show_avg_score:
	cmp buffer[0], 's'
	jne chk_do_show_avg_score_end
	cmp buffer[1], 'h'
	jne chk_do_show_avg_score_end
	cmp buffer[2], 'o'
	jne chk_do_show_avg_score_end
	cmp buffer[3], 'w'
	jne chk_do_show_avg_score_end
	cmp buffer[4], ' '
	jne chk_do_show_avg_score_end
	cmp buffer[5], 'a'
	jne chk_do_show_avg_score_end
	cmp buffer[6], 'v'
	jne chk_do_show_avg_score_end
	cmp buffer[7], 'g'
	jne chk_do_show_avg_score_end
	cmp buffer[8], 0
	jne chk_do_show_avg_score_end

	mov byte ptr instru_ok, 1
	ret

chk_do_show_avg_score_end:
ret

;========================================
;		Rewrite int8 vector table
;========================================
RewriteInt8:
	push ax
	push cx
	push ds
	push es
	push si
	push di

	mov ax, code					;source code
	mov ds, ax
	mov si, offset Show_time

	mov ax, 0						;dest address. 0:200h
	mov es, ax
	mov di, 200h

	mov cx, offset Show_time_end - offset Show_time
	cld								;copy the code to safe address
	rep movsb

	mov ax, es:[32]					;the original IP
	mov es:[202h], ax				;copy ip to safe address
	;using 202h because the `jmp` instruction is 2 bytes long

	mov ax, es:[34]					;the original CS
	mov es:[204h], ax				;copy cs to safe address

	mov word ptr es:[32], 200h		;rewrite IP
	mov word ptr es:[34], 0			;rewrite CS

	pop di
	pop si
	pop es
	pop ds
	pop cx
	pop ax
ret

;========================================
;		Restore int8 vector table
;========================================
RestoreInt8:
	push ax
	push ds

	mov ax, 0
	mov ds, ax

	mov ax, ds:[202h]			;restore the original int9 address
	mov ds:[32], ax
	mov ax, ds:[204h] 
	mov ds:[34], ax
	
	pop ds
	pop ax
ret

;========================================
;		Show_time: the new int8 func
;========================================
Show_time:
	jmp Show_time_stt
	db 8 dup(0)						;save the original int8 func address
Show_time_stt:
	push es
	push ax
	push di
	push cx
	push bx

	mov ax, 0
	mov es, ax
	pushf							;triger the original int8 func
	call dword ptr es:[202h]

	mov ax, 0b800h
	mov es, ax
	lea di, ds:[160*0 + 2*67]

	output_char 't', 111b
	output_char 'i', 111b
	output_char 'm', 111b
	output_char 'e', 111b
	output_char ' ', 111b

	mov ah, 2ch
	int 21h

	mov bx, 10
	mov ax, 0

	mov al, ch
	mov ah, 0
	div bl
	add ah, '0'
	add al, '0'
	output_char al, 111b
	output_char ah, 111b
	output_char ':', 111b

	mov al, cl
	mov ah, 0
	div bl
	add ah, '0'
	add al, '0'
	output_char al, 111b
	output_char ah, 111b
	output_char ':', 111b

	mov al, dh
	mov ah, 0
	div bl
	add ah, '0'
	add al, '0'
	output_char al, 111b
	output_char ah, 111b

	pop bx
	pop cx
	pop di
	pop ax
	pop es
	iret
Show_time_end: nop

code ends
end start
